"""WebSocket服务模块
用于向前端发送实时任务执行更新
"""
import json
import requests
from typing import Optional, Dict, Any
from flask_socketio import SocketIO
from services.shared.logger import get_logger
from services.shared.log_utils import log_error, log_info, log_system_event

logger = get_logger('shared.websocket')


class WebSocketService:
    """WebSocket服务类"""
    
    def __init__(self):
        self.socketio: Optional[SocketIO] = None
        self.web_service_url = None
    
    def init_socketio(self, socketio: SocketIO):
        """初始化SocketIO实例"""
        import os
        # 只在web服务中初始化socketio，在Celery worker中不初始化
        if os.environ.get('SERVICE_TYPE') != 'celery-workers':
            self.socketio = socketio
        else:
            # 在Celery worker中，保持socketio为None，强制使用HTTP发送
            self.socketio = None
    
    def set_web_service_url(self, url: str):
        """设置web服务的URL，用于HTTP请求发送WebSocket消息"""
        self.web_service_url = url
    
    def _emit_via_http(self, event_type: str, event_data: Dict[str, Any], room: str):
        """通过HTTP请求发送WebSocket消息"""
        if not self.web_service_url:
            logger.warning('WebSocket服务URL未设置，无法发送HTTP请求')
            return False
        
        logger.debug(f"通过HTTP发送WebSocket消息: {event_type} 到房间 {room}")
        
        try:
            url = f"{self.web_service_url}/api/websocket/emit"
            payload = {
                'event_type': event_type,
                'event_data': event_data,
                'room': room
            }
            response = requests.post(url, json=payload, timeout=5)
            if response.status_code == 200:
                logger.debug(f'通过HTTP发送WebSocket消息成功: {event_type} 到房间 {room}')
                log_info(
                    "websocket_http_emit_success",
                    f"WebSocket HTTP消息发送成功: {event_type}",
                    details=json.dumps({
                        "event_type": event_type,
                        "room": room,
                        "web_service_url": self.web_service_url
                    }, ensure_ascii=False)
                )
                return True
            else:
                logger.error(f'通过HTTP发送WebSocket消息失败: {response.status_code} - {response.text}')
                log_error(
                    "websocket_http_emit_failed",
                    f"WebSocket HTTP消息发送失败: {event_type}",
                    details=json.dumps({
                        "event_type": event_type,
                        "room": room,
                        "status_code": response.status_code,
                        "response_text": response.text[:200],
                        "web_service_url": self.web_service_url
                    }, ensure_ascii=False)
                )
                return False
        except Exception as e:
            logger.error(f'HTTP发送WebSocket消息异常: {str(e)}')
            log_error(
                "websocket_http_emit_exception",
                f"WebSocket HTTP消息发送异常: {event_type}",
                details=json.dumps({
                    "event_type": event_type,
                    "room": room,
                    "error": str(e),
                    "web_service_url": self.web_service_url
                }, ensure_ascii=False)
            )
            return False
    
    def emit_execution_update(self, execution_id: str, data: Dict[str, Any]):
        """发送执行记录更新"""
        if not self.socketio:
            return
        
        try:
            room = f'execution_{execution_id}'
            # 直接发送WebSocket消息，不检查应用上下文
            self.socketio.emit('execution_update', data, room=room)
            logger.debug(f'发送执行更新到房间 {room}: {data.get("status", "unknown")}')
        except Exception as e:
            # 静默处理错误，避免影响任务执行
            logger.warning(f'WebSocket推送失败: {str(e)}')
            pass
    
    def emit_execution_output(self, execution_id: str, output_type: str, content: str, is_realtime: bool = False):
        """发送执行输出更新"""
        room = f'execution_{execution_id}'
        data = {
            'type': 'output',
            'output_type': output_type,  # 'stdout' 或 'stderr'
            'content': content,
            'is_realtime': is_realtime,
            'timestamp': self._get_current_timestamp(),
            'execution_id': execution_id
        }
        
        try:
            # 优先使用SocketIO直接发送
            if self.socketio:
                self.socketio.emit('execution_output', data, room=room)
                logger.debug(f'发送输出更新到房间 {room}: {output_type} ({len(content)} 字符)')
                log_info(
                    "websocket_output_emit_success",
                    f"WebSocket输出消息发送成功: {output_type}",
                    details=json.dumps({
                        "execution_id": execution_id,
                        "output_type": output_type,
                        "content_length": len(content),
                        "is_realtime": is_realtime,
                        "room": room
                    }, ensure_ascii=False)
                )
            else:
                # 如果没有SocketIO实例，通过HTTP发送
                logger.debug(f"SocketIO实例不可用，通过HTTP发送输出消息: {execution_id}")
                self._emit_via_http('execution_output', data, room)
        except Exception as e:
            # 如果SocketIO发送失败，尝试HTTP发送
            logger.warning(f'SocketIO推送失败，尝试HTTP发送: {str(e)}')
            log_error(
                "websocket_output_emit_fallback",
                f"WebSocket输出消息SocketIO发送失败，回退到HTTP: {execution_id}",
                details=json.dumps({
                    "execution_id": execution_id,
                    "output_type": output_type,
                    "error": str(e),
                    "room": room
                }, ensure_ascii=False)
            )
            self._emit_via_http('execution_output', data, room)
    
    def emit_execution_status_change(self, execution_id: str, status: str, **kwargs):
        """发送执行状态变化"""
        room = f'execution_{execution_id}'
        data = {
            'type': 'status_change',
            'status': status,
            'timestamp': self._get_current_timestamp(),
            'execution_id': execution_id,
            **kwargs
        }
        
        try:
            # 优先使用SocketIO直接发送
            if self.socketio:
                self.socketio.emit('execution_status_change', data, room=room)
                logger.debug(f'发送状态变化到房间 {room}: {status}')
            else:
                # 如果没有SocketIO实例，通过HTTP发送
                self._emit_via_http('execution_status_change', data, room)
        except Exception as e:
            # 如果SocketIO发送失败，尝试HTTP发送
            logger.warning(f'SocketIO推送失败，尝试HTTP发送: {str(e)}')
            self._emit_via_http('execution_status_change', data, room)
    
    def emit_script_test_output(self, test_id: str, output_type: str, content: str):
        """发送脚本测试输出更新
        
        Args:
            test_id: 测试ID
            output_type: 输出类型 ('stdout', 'stderr', 'status', 'error')
            content: 输出内容
        """
        room = f'script_test_{test_id}'
        data = {
            'type': 'script_test_output',
            'output_type': output_type,
            'content': content,
            'timestamp': self._get_current_timestamp(),
            'test_id': test_id
        }
        
        try:
            # 优先使用SocketIO直接发送
            if self.socketio:
                self.socketio.emit('script_test_output', data, room=room)
                logger.debug(f'发送脚本测试输出到房间 {room}: {output_type} ({len(content)} 字符)')
            else:
                # 如果没有SocketIO实例，通过HTTP发送
                self._emit_via_http('script_test_output', data, room)
        except Exception as e:
            # 如果SocketIO发送失败，尝试HTTP发送
            logger.warning(f'SocketIO推送失败，尝试HTTP发送: {str(e)}')
            self._emit_via_http('script_test_output', data, room)
    
    def _get_current_timestamp(self) -> str:
        """获取当前时间戳"""
        from datetime import datetime
        return datetime.now().isoformat()


# 全局WebSocket服务实例
websocket_service = WebSocketService()


def get_websocket_service() -> WebSocketService:
    """获取WebSocket服务实例"""
    return websocket_service